package client

import (
	"fmt"
	"github.com/ethereum/go-ethereum/ethclient"
	models "go-chain-api/internal/model"
	"gorm.io/gorm"
	"log"
	"strings"
	"sync"
)

// NodeManager 结构体用于管理一组以太坊 RPC 节点
type NodeManager struct {
	chains map[string][]*ethclient.Client // 保存所有链的以太坊客户端
	index  map[string]int                 // 每条链当前活动节点的索引
	url    map[string]string              // 每条链当前活动节点的url
	mu     sync.Mutex                     // 用于同步对 index 的访问
}

func NewNodeManager(db *gorm.DB) (*NodeManager, error) {
	manager := &NodeManager{
		chains: make(map[string][]*ethclient.Client),
		index:  make(map[string]int),
		url:    make(map[string]string),
	}

	chainConfigs, err := GetChainConfigs(db) // 从GetChainConfigs获取链配置信息
	if err != nil {
		return nil, fmt.Errorf("获取链配置失败: %v", err)
	}

	if len(chainConfigs) == 0 {
		return nil, fmt.Errorf("没有可用的链配置")
	}

	for _, config := range chainConfigs {
		var validClients []*ethclient.Client
		for _, url := range config.RrcUrls {
			fmt.Println(strings.TrimSpace(url.Url))
			client, err := ethclient.Dial(strings.TrimSpace(url.Url))
			if err != nil {
				log.Printf("无法连接到 %s 节点 %s: %v", config.ChainName, url, err)
				continue // 如果创建客户端失败，继续尝试下一个
			}
			validClients = append(validClients, client)
			manager.url[config.ChainName] = url.Url
		}
		if len(validClients) > 0 {
			manager.chains[config.ChainName] = validClients
			manager.index[config.ChainName] = 0 // 初始化索引为0
		} else {
			log.Printf("所有 %s 节点都无法连接", config.ChainName)
		}
	}

	if len(manager.chains) == 0 {
		return nil, fmt.Errorf("没有任何节点可以连接")
	}

	return manager, nil
}

func (m *NodeManager) GetClient(chainName string) (*ethclient.Client, error) {
	chainName = strings.ToUpper(chainName)
	m.mu.Lock()         // 加锁以同步对 index 的访问
	defer m.mu.Unlock() // 函数结束时解锁

	clients, ok := m.chains[chainName]
	if !ok || len(clients) == 0 {
		return nil, fmt.Errorf("未找到名为 %s 的链或该链没有可用的节点", chainName)
	}
	index := m.index[chainName]
	fmt.Println(index)
	if index < 0 || index >= len(clients) {
		return nil, fmt.Errorf("当前索引 %d 超出有效范围", index)
	}

	client := clients[index]
	return client, nil
}

// SwitchToNextNode 方法在遇到错误时尝试切换到下一个节点
func (m *NodeManager) SwitchToNextNode(chainName string) error {
	m.mu.Lock()         // 加锁以同步对 index 的访问
	defer m.mu.Unlock() // 函数结束时解锁

	if _, ok := m.chains[chainName]; !ok {
		return fmt.Errorf("未找到名为 %s 的链", chainName)
	}

	m.index[chainName] = (m.index[chainName] + 1) % len(m.chains[chainName]) // 切换到下一个节点，如果到达末尾则循环到开始
	return nil
}
func (m *NodeManager) GetUrl(chainName string) string {
	return m.url[chainName]
}

func GetChainConfigs(db *gorm.DB) ([]*models.ChainConfig, error) {
	var chainConfigs []*models.ChainConfig
	// Redis中没有数据或反序列化失败，从数据库获取
	result := db.Preload("RrcUrls").Find(&chainConfigs)
	if result.Error != nil {
		return nil, result.Error
	}
	return chainConfigs, nil
}
